package rs.etf.kdp.server;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JTextArea;

/**
 * @author Djordje Vukovic
 * @version 1.0
 * @created 20-May-2011 2:30:23 AM
 */
public class Heartbeater extends Thread{
	
	
	
	int timeInterval;
	AvailableNodes nodes;
	List<NodeInfo> nodesStatus;
	private JTextArea out;
	private CurrentSimulations currentSimulations;
	
	public Heartbeater(int numberOfSeconds, AvailableNodes anodes, CurrentSimulations currentSimulations, JTextArea out){
		this.currentSimulations = currentSimulations;
		this.out = out;
		timeInterval = numberOfSeconds;
		nodes = anodes;
		nodesStatus = new ArrayList<NodeInfo>();
		List<Node> ws = nodes.getAvailableWorkstations();
		for(Node n : ws)
		{
			nodesStatus.add(new NodeInfo(n.getIpAddress(), n.getNameOfNode()));
		}
	}

	public void run()
	{
		
		try
		{
			while(true)
			{
				List<Node> avail = nodes.getAvailableWorkstations();
				if(avail.isEmpty())
				{
					Thread.sleep(timeInterval * 1000);
					continue;
				}
				try {
					sendHello(avail);
				} catch (IOException e) {
					e.printStackTrace();
				}
				Thread.sleep(timeInterval * 1000);

				//if(checkResult())
				//{
					//for(int i=0; i<nodesStatus.size(); i++)
					//{
						//nodesStatus.get(i).setOk(false);
					//}
					//out.append("\nAll workstations respond to heartbeat");
				//} else
				//{
				//	out.append("\nNot all workstations responded to heartbeat. Some simulations may be restarted");
				//}
			}
		} catch(InterruptedException ex)
		{
			return;
		}
		
		
	}
	
	private void sendHello(List<Node> nodes) throws IOException
	{
		//Socket socketToWS = null;
		ObjectOutputStream oos;
		String command = "heartbeat";
		
		for(int i=0; i< nodes.size(); i++)
		{
			Node node = nodes.get(i);
			SendPermission permission = node.getPermission();
			permission.requireSend();
			//socketToWS = node.getSocketToNode();
			//oos = new ObjectOutputStream(socketToWS.getOutputStream());
			for(NodeInfo j : nodesStatus)
			{
				if(j.getIpAddress().equals(node.getIpAddress())) j.setSent(true);
			}
			
			oos = node.getOutput();
			try {
				oos.writeObject(command);
			} catch (Exception e) {
				out.append("\nClosed socket in sendHello, workstation is not valid anymore");
				detectedUnavailableNode(node);
			}
			permission.releaseSent();
		}
	}
	
//	private boolean checkResult()
//	{
//		boolean res = true;
//		for(NodeInfo ni : nodesStatus)
//		{
//			if(!ni.isOk() && ni.isSent())
//			{
//				Node n = nodes.getNodeByIp(ni.getIpAddress());
//				detectedUnavailableNode(n);
//				res = false;
//			}
//		}
//		return res;
//	}
	
	public void detectedUnavailableNode(Node node)
	{
		List<Simulation> simulationsRunning = node.getSimulationsRunning();
		nodes.removeNode(node);
		//int size = simulationsRunning.size();
		for(int i = 0; i < simulationsRunning.size(); i++)
		{
			Simulation s = simulationsRunning.get(i);
			s.restartThisSimulation(currentSimulations);
		}
		
		nodes.removeByWorkstationName(node.getNameOfNode());
		removeFromNodesStatus(node.getNameOfNode());
	}

	public int getTimeInterval() {
		return timeInterval;
	}

	public void setTimeInterval(int timeInterval) {
		this.timeInterval = timeInterval;
	}

	public AvailableNodes getNodes() {
		return nodes;
	}

	public void setNodes(AvailableNodes nodes) {
		this.nodes = nodes;
	}

	public List<NodeInfo> getNodesStatus() {
		return nodesStatus;
	}

	public void setNodesStatus(List<NodeInfo> nodesStatus) {
		this.nodesStatus = nodesStatus;
	}
	
	public synchronized void addToNodesStatus(String address, String name)
	{
		NodeInfo newInfo = new NodeInfo(address, name);
		nodesStatus.add(newInfo);
	}
	
	public CurrentSimulations getCurrentSimulations() {
		return currentSimulations;
	}

	public void setCurrentSimulations(CurrentSimulations currentSimulations) {
		this.currentSimulations = currentSimulations;
	}

	public synchronized void removeFromNodesStatus(String name)
	{
		int size = nodesStatus.size();
		for(int i=0; i < size; i++)
		{
			try {
				if(nodesStatus.get(i).getName().equals(name))
				{
					nodesStatus.remove(i);
				}
			} catch (IndexOutOfBoundsException iob)
			{
				System.out.println("Cantt catch " + i + "\n");
				System.out.println(nodesStatus.size());
			}
		}
	}
	

	
}